varnish
==================================================
一：缓存简介

1.1：缓存命中率：hit/(hit+miss)
        文档命中率：从文档个数进行衡量。
        字节命中率：从内容的大小进行衡量。

1.2：缓存的生命周期
        缓存清理：
            缓存项过期
            缓存空间用尽：LRU 

1.3：是否缓存
        私有数据，不可缓存

1.4：缓存的处理步骤
    接收请求 --> 解析请求（提取请求的URL及各种首部）--> 查询缓存 --> 新鲜度检测 --> 构建响应报文 --> 发送响应 --> 记录日志 

1.5：http cache
    squid varnish
    httpd，nginx

1.6：缓存控制机制
    缓存控制机制：
        过期日期：
            HTTP/1.0 Expires
                Expires:Fri, 20 May 2016 02:03:18 GMT
        过期时间：
            HTTP/1.1 Cache-Control：max-age
                Cache-Control:no-transform, max-age=3600

        Cache-Control：
            cahe-request-directive=
                    no-cache
                |   no-store
                |   max-age
                |   max-stale
                |   min-fresh
            cache-response-directive=
                    public
                |   private
                |   no-cache
                |   no-store
                |   must-revalidate
                |   max-age
                |   s-max-age

1.7：新鲜度检测机制
            有效性再验正：revalidate
                如果原始内容未改变，则仅响应首部（不用附带body部分）；响应码为304（Not Modified）
                如果原始内容发生了改变，则正常响应，响应码为200
                如果原始内容消失，则响应为404，此时缓存中的缓存项也应该被删除
            
            条件式请求首部
                If-Modified-Since：基于原始内容的最近一个修改的时间戳进行
                If-Unmodified-Since
                If-Match
                If-None-Match：基于Etag的比较进行
            

二：varnish

    官网：http://www.varnish-cache.org
    官网下载地址：http://www.varnish-cache.org/releases/index.html
    RedHat安装：http://www.varnish-cache.org/releases/install_redhat.html#install-redhat
    结构图：
    <img src="7.png" alt="">
    <img src="8.png" alt="">

2.1：varnish通过可以基于文件系统接口进行访问的共享内在区域来记录日志（shared memory log）；90MB；
        分为两部分：
            前半部分是计数器
            后半部分为客户端请求的数据

2.2：vcl：
        配置缓存策略的工具
        依赖 gcc
        基于“域”的配置语言
        状态引擎：state engine
        VCL存在多个状态引擎，状态之间存在相关性，但彼此间相互隔离；每个引擎使用return(x)来退出当前状态，并转入下一状态；
            不同的状态的引擎，其x是不尽相同；

2.3： varnish缓存内容的存储
        (1) file：自管理的文件系统，黑盒。
        (2) malloc：使用malloc()库调用在varnish启动时向内存申请指定大小的空间。
        (3) persistent：与file功能相同 。

2.4：指明缓存存储：-s [name=]type[,options]
        malloc[,size]
        file[,path[,size[,granularity]]]
        persistent,path,size
        -p param=value 

2.5：请求处理流程：
        (1) 请求的为可缓存。
            (a) 命中：通过本地缓存响应。
            (b) 未命中：到后端服务取得相应内容。
                可缓存对象：先缓存再响应。
                    缓存。
                        定义缓存时间。
                        自定义缓存键。
                不可缓存对象：不缓存而直接响应。
        (2) 请求的为不可缓存。
            (a) 到后端服务器取得相应内容。

2.6：vcl的语法：
                (1) //， #，/*...*/：注释
                (2) sub $name：定义子例程。
                (3) 不支持循环，支持条件判断。
                (4) 有内建变量。
                (5) 使用终止语句return，没有返回值。
                (6) 操作符：=, ==, !=, ~, &&, ||
                (7) (?i) 不区分大小写

2.7：报文流向
        varnish finate state machine：
            vcl_recv
            vcl_hash
                hit: vcl_hit
                miss: vcl_miss
                purge: vcl_purge
                pipe: vcl_pipe
                pass, hit_for_pass: vcl_pass
            vcl_backend_fetch
            vcl_backend_response
            vcl_backend_error
            vcl_synth
            vcl_deliver

        数据报文处理流向：
            vcl_recv --> vcl_hash -->
                (1) vcl_hit --> 
                    (a) vcl_deliver
                    (b) vcl_pass --> vcl_backend_fetch
                (2) vcl_miss -->
                    (a) vcl_pass
                    (b) vcl_backend_fetch
                (3) vcl_purge -->
                    vcl_synth
                (4) vcl_pipe -->

            vcl_backend_fetch -->
                vcl_backend_response --> vcl_deliver
                vcl_backend_error 

2.8：vcl：变量
            内建变量：
                    req.*：由客户发来的http请求相关；
                        req.http.*：请求报文各首部；
                    bereq.*：由varnish向backend主机发出的http请求；
                        bereq.http.*
                    beresp.*：由backend主机发来的http响应报文；
                        beresp.http.*
                    resp.*：由varnish响应给client的http的响应报文；
                        resp.http.*：响应报文的各首部；
                    obj.*：存储在缓存空间中的缓存对象属性；只读；
                    
                    client.*, server.*, storage.*：可用在所有的client side的sub routines中；
                自定义：set 

            常用的变量：
                bereq：
                    bereq.http.HEADERS：
                    bereq.request：请求方法；
                    bereq.url：请求的url；
                    bereq.proto：协议版本；
                    bereq.backend：指明要调用的后端主机；
                    
                beresp：
                    beresp.proto：
                    beresp.status：响应的状态码；
                    beresp.reason：
                    beresp.backend.name：
                    beresp.http.HEADERS：
                    beresp.ttl：后端服务器响应中的内容的余下的生存时长；
                    
                obj
                    obj.hits：此对象从缓存中命中的次数；
                    obj.ttl：对象的ttl值； 
                    
                server:
                    server.ip
                    server.hostname
                    
                req.method：请求方法；
                req.url：请求的url；




三：配置文件

3.1：/etc/varnish/varnish.params

---------------------------file start------------------------------------

        是否启用 systemd reload 重新加载
        RELOAD_VCL=1

        主配置文件
        VARNISH_VCL_CONF=/etc/varnish/default.vcl

        绑定端口或地址
        # VARNISH_LISTEN_ADDRESS=192.168.1.5
        # VARNISH_LISTEN_PORT=6081
        VARNISH_LISTEN_PORT=80

        # 管理接口和地址
        VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1
        VARNISH_ADMIN_LISTEN_PORT=6082

        # 共享秘钥
        VARNISH_SECRET_FILE=/etc/varnish/secret

        # 存储文件与类型
        VARNISH_STORAGE="file,/var/lib/varnish/varnish_storage.bin,1G"

        # 默认 TTL 值
        VARNISH_TTL=120

        # 使用的用户和组
        VARNISH_USER=varnish
        VARNISH_GROUP=varnish

        # 其他的配置文件
        #DAEMON_OPTS="-p thread_pool_min=5 -p thread_pool_max=500 -p thread_pool_timeout=300"

---------------------------file end------------------------------------


四：应用

4.1：判断文件是否缓存

    ~]# vi /etc/varnish/default.vcl
---------------------------file start------------------------------------
        vcl 4.0;
        backend default {
            .host = "172.18.21.72";
            .port = "80";
        }
        sub vcl_recv {
        }
        sub vcl_backend_response {
        }
        sub vcl_deliver {
                if (obj.hits>0) {
                    set resp.http.X-Cache = "HIT";
                } else {
                    set resp.http.X-Cache = "MISS";
                }
        }
---------------------------file end------------------------------------

    编译与使用：
        ~]# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
        varnish]# vcl.load test1 default.vcl
            200
            VCL compiled.
        varnish]# vcl.use test1
            200        
            VCL 'test1' now active

    测试：查看浏览器 Response Headers
        1：首次响应：X-Cache: MISS
        2：后续响应：X-Cache:HIT


4.2：强制对某资源的请求不检查缓存

    ~]# vi /etc/varnish/default.vcl
---------------------------file start------------------------------------
vcl 4.0;
backend default {
    .host = "172.18.21.72";
    .port = "80";
}
sub vcl_recv {
    if (req.url ~ "(?i)^/login" || req.url ~ "(?i)^/admin") {
        return(pass);
    }   
}
sub vcl_backend_response {
}
sub vcl_deliver {
        if (obj.hits>0) {
            set resp.http.X-Cache = "HIT";
        } else {
            set resp.http.X-Cache = "MISS";
        }   
}
---------------------------file end------------------------------------

    编译与使用：
        ~]# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
        varnish]# vcl.load test2 default.vcl
            200
            VCL compiled.
        varnish]# vcl.use test2
            200
        VCL 'test2' now active

    测试：查看浏览器 Response Headers
        访问 login admin 目录下始终响应为：X-Cache: MISS


4.3：对特定类型的资源，取消其私有标识，并强行设定缓存时长

    ~]# vi /etc/varnish/default.vcl
---------------------------file start------------------------------------
vcl 4.0;
backend default {
    .host = "172.18.21.72";
    .port = "80";
}
sub vcl_recv {
}
sub vcl_backend_response {
    if (beresp.http.cache-control !~ "s-maxage") {
            if (bereq.url ~ "(?i)\.jpg$") {
                set beresp.ttl = 7200s;
                unset beresp.http.Set-Cookie;
            }
            if (bereq.url ~ "(?i)\.css$") {
                set beresp.ttl = 3600s;
                unset beresp.http.Set-Cookie;
            }
    }
}
sub vcl_deliver {
        if (obj.hits>0) {
            set resp.http.X-Cache = "HIT";
        } else {
            set resp.http.X-Cache = "MISS";
        }
}
---------------------------file end------------------------------------
    配置与查看同上


4.4：缓存对象修剪,仅允许本机和授权域访问

    ~]# vi /etc/varnish/default.vcl
---------------------------file start------------------------------------
    vcl 4.0;
    backend default {
        .host = "172.18.21.72";
        .port = "80";
    }
    acl purgers {
        "127.0.0.0"/8;
        "172.18.0.0"/16;
    }
    sub vcl_purge {
        return (synth(200, "Purged"));
    }
    sub vcl_recv {
        if (req.method == "PURGE") {
            if (!client.ip ~ purgers) {
                return(synth(405,"Purging not allow for"+client.ip));
            }
            return(purge);
        }
    }
    sub vcl_backend_response {
        if (beresp.http.cache-control !~ "s-maxage") {
                if (bereq.url ~ "(?i)\.jpg$") {
                    set beresp.ttl = 7200s;
                    unset beresp.http.Set-Cookie;
                }
                if (bereq.url ~ "(?i)\.css$") {
                    set beresp.ttl = 3600s;
                    unset beresp.http.Set-Cookie;
                }
        }
    }
    sub vcl_deliver {
            if (obj.hits>0) {
                set resp.http.X-Cache = "HIT";
            } else {
                set resp.http.X-Cache = "MISS";
            }
    }
---------------------------file end------------------------------------

    清理缓存：
    ~]# curl -X PURGE http://172.18.21.71/default.jpg


4.5：设定多个后端主机：动静分离

    ~]# vi /etc/varnish/default.vcl
---------------------------file start------------------------------------
    vcl 4.0;
    backend default {
        .host = "172.18.21.72";
        .port = "80";
    }
    backend appsrv {
        .host = "172.18.21.73";
        .port = "80";
    }
    sub vcl_recv {
     if (req.url ~ "(?i)\.php$") {
             set req.backend_hint = appsrv;
         } else {
             set req.backend_hint = default;
     }
    }
    sub vcl_backend_response {
    }
    sub vcl_deliver {
            if (obj.hits>0) {
                set resp.http.X-Cache = "HIT";
            } else {
                set resp.http.X-Cache = "MISS";
            }   
    }
---------------------------file end------------------------------------


4.6：Directors：轮询调度

    ~]# vi /etc/varnish/default.vcl
---------------------------file start------------------------------------
    vcl 4.0;
    import directors;
    backend websrv1 {
        .host = "172.18.21.72";
        .port = "80";
    }
    backend websrv2 {
        .host = "172.18.21.73";
        .port = "80";
    }
    sub vcl_init {
        new websrvs = directors.round_robin();
        websrvs.add_backend(websrv1);
        websrvs.add_backend(websrv2);
    }
    sub vcl_recv {
        set req.backend_hint = websrvs.backend();
        if (req.url ~ "/") {
            return(pass);
        }
    }
    sub vcl_backend_response {
    }
    sub vcl_deliver {
            if (obj.hits>0) {
                set resp.http.X-Cache = "HIT";
            } else {
                set resp.http.X-Cache = "MISS";
            }
    }
---------------------------file end------------------------------------


4.7：健康状态检测
    ~]# vi /etc/varnish/default.vcl
---------------------------file start------------------------------------
    vcl 4.0;
    import directors;
    backend websrv1 {
        .host = "172.18.21.72";
        .port = "80";
        .probe = {
            # 检测的url
            .url = "/";
            # 检测时间
            .interval = 1s;
            # 最后几次检测的数据
            .window = 8;
            # 最后几次检测的成功数
            .threshold = 5;
            # 超市时长
            .timeout = 2s;
        }
    }
    backend websrv2 {
        .host = "172.18.21.73";
        .port = "80";
        .probe = {
            .url = "/";
            .interval = 1s;
            .window = 8;
            .threshold = 5;
            .timeout = 2s;
        }
    }
    sub vcl_init {
        new websrvs = directors.round_robin();
        websrvs.add_backend(websrv1);
        websrvs.add_backend(websrv2);
    }
    sub vcl_recv {
        set req.backend_hint = websrvs.backend();
        if (req.url ~ "/") {
            return(pass);
        }
    }
    sub vcl_backend_response {
    }
    sub vcl_deliver {
            if (obj.hits>0) {
                set resp.http.X-Cache = "HIT";
            } else {
                set resp.http.X-Cache = "MISS";
            }
    }
---------------------------file end------------------------------------
    测试：关闭与开启后端服务查看。
    备注：如果应用服务器停止服务时，页面会显示 503。注意检测时长。


五：常用相关命令

5.1：varnishtop
        ~]# varnishtop

5.2：varnishlog
        ~]# varnishlog

5.3：varnishncsa
        ~]# varnishncsa

5.4：varnishstat
        ~]# varnishstat